package me.flyray.crm.core.blockchain.block;

import me.flyray.crm.core.blockchain.dpos.DelegatedProofOfStake;
import me.flyray.crm.core.blockchain.transaction.DposTransaction;
import me.flyray.crm.core.blockchain.transaction.MerkleTree;
import me.flyray.crm.core.blockchain.util.ByteUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.time.Instant;

/**
 * block 区块
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class DposBlock {
    /**
     * 区块hash值
     */
    private String hash;
    /**
     * 前一个区块的hash值
     */
    private String prevBlockHash;
    /**
     * 交易信息
     */
    private DposTransaction[] transactions;
    /**
     * 区块奖励交易
     */
    private DposTransaction rewardTransaction;
    /**
     * 区块创建时间(单位:秒)
     */
    private long timeStamp;

    /**
     * 区块高度
     */
    private int height;
    /**
     * 区块奖励数额
     */
    private double reward;


    /**
     * <p> 创建创世区块 </p>
     *
     * @param coinbase
     * @return
     */
    public static DposBlock newGenesisBlock(DposTransaction coinbase,Long platformId) {
        return DposBlock.newBlock(ByteUtils.ZERO_HASH, new DposTransaction[]{coinbase},platformId);
    }

    /**
     * <p> 创建新区块 </p>
     *
     * @param previousHash
     * @param transactions
     * @return
     */
    public static DposBlock newBlock(String previousHash, DposTransaction[] transactions,Long platformId) {
        DposBlock block = new DposBlock("", previousHash, transactions, null, Instant.now().getEpochSecond(), 0, 0);
        DelegatedProofOfStake dpos = DelegatedProofOfStake.newDelegatedProofOfStake(block, platformId);
        String blockHash = dpos.run();
        block.setHash(blockHash);
        return block;
    }

    /**
     * 对区块中的交易信息进行Hash计算
     *
     * @return
     */
    public byte[] hashTransaction() {
        if (this.getRewardTransaction() != null) {
            byte[][] txIdArrays = new byte[this.getTransactions().length + 1][];
            for (int i = 0; i < this.getTransactions().length; i++) {
                txIdArrays[i] = this.getTransactions()[i].hash();
            }
            txIdArrays[this.getTransactions().length] = getRewardTransaction().hash();
            return new MerkleTree(txIdArrays).getRoot().getHash();
        } else {
            byte[][] txIdArrays = new byte[this.getTransactions().length][];
            for (int i = 0; i < this.getTransactions().length; i++) {
                txIdArrays[i] = this.getTransactions()[i].hash();
            }
            return new MerkleTree(txIdArrays).getRoot().getHash();
        }
    }




}
